package com.atguigu.tingshu.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AlbumFeignClient albumFeignClient;

    /**
     * 订单页确认数据参数汇总
     * @param tradeVo {itemType:"项目类型",:itemId:"项目",trackCount:"声音数量"}
     * @return 订单vo对象->为后续提交订单准备
     */
    @Override
    public OrderInfoVo getOrderInfoData(TradeVo tradeVo) {
        // 获取用户信息
        Long userId = AuthContextHolder.getUserId();

        // 1. 创建订单信息VO
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        // 1.1. 声明默认价格（原价、减免价、订单价）
        BigDecimal originalAmount = new BigDecimal("0.00");
        BigDecimal derateAmount = new BigDecimal("0.00");
        BigDecimal orderAmount = new BigDecimal("0.00");

        // 1.2. 声明订单明细列表集合order_detail
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();

        // 1.3. 声明减免信息列表集合order_derate
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        // 2. 处理VIP会员（允许重复）
        if (SystemConstant.ORDER_ITEM_TYPE_VIP.equals(tradeVo.getItemType())){
            // 2.1 根据选择套餐ID远程调用“用户服务”获取 套餐信息
            VipServiceConfig vipServiceConfig = userFeignClient.getVipServiceConfig(tradeVo.getItemId()).getData();
            Assert.notNull(vipServiceConfig,"套餐{}信息为空",tradeVo.getItemId());
            // 2.2 为订单VO中商品价格赋值-原价、减免价、订单价
            originalAmount = vipServiceConfig.getPrice();
            derateAmount = vipServiceConfig.getDiscountPrice();
            orderAmount = originalAmount.subtract(derateAmount);
            // 2.3 封装订单明细列表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName("套餐：" + vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemPrice(originalAmount);
            orderDetailVoList.add(orderDetailVo);

            // 2.4 封装减免信息列表
            if (originalAmount.compareTo(orderAmount) != 0){
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("VIP套餐限时优惠减免：" + derateAmount + "￥");
                orderDerateVoList.add(orderDerateVo);
            }


        }else if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())){
            // 3. 处理专辑（不允许重复）
            // 3.1 远程调用用户服务判断用户专辑是否购买
            Boolean isPaid = userFeignClient.isPaidAlbum(tradeVo.getItemId()).getData();
            if (isPaid){
                throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
            }
            // 3.2 远程调用用户服务得到用户身份
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            Assert.notNull(userInfoVo,"用户{}不存在！",userId);
            // 3.3 远程调用专辑服务，根据专辑id得到专辑信息
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(tradeVo.getItemId()).getData();
            Assert.notNull(albumInfo,"专辑{}不存在！",tradeVo.getItemId());
            // 3.4 封装专辑的信息价格、折扣（区分普通用户和VIP用户）
            originalAmount = albumInfo.getPrice(); // 100
            orderAmount = originalAmount;  // 100
            int isVip = userInfoVo.getIsVip().intValue();
            // 3.4.1 判断当前专辑是否有普通用户折扣（是否不等于-1）
            if (albumInfo.getDiscount().intValue() != -1){
               // 且 当前用户是普通用户/VIP过期
                if (isVip == 0 || (isVip == 1 && new Date().after(userInfoVo.getVipExpireTime()))){
                    // 原价 * 折扣（8折） / 10, 避免精度损失保留2位，四舍五入
                   orderAmount = originalAmount.multiply(albumInfo.getDiscount()).divide(new BigDecimal("10"),2,RoundingMode.HALF_UP);
                }
            }
            // 3.4.2 判断当前专辑是否是VIP用户折扣
            if (albumInfo.getDiscount().intValue() != -1){
                if (isVip == 1 && userInfoVo.getVipExpireTime().after(new Date())){
                    orderAmount = originalAmount.multiply(albumInfo.getVipDiscount()).divide(new BigDecimal("10"),2,RoundingMode.HALF_UP);
                }
            }
            derateAmount = originalAmount.subtract(orderAmount);

            // 3.5 封装专辑订单明细表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName("专辑：" + albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(albumInfo.getPrice());
            orderDetailVoList.add(orderDetailVo);

            // 3.6 封装专辑订单减免表
            if (derateAmount.compareTo(new BigDecimal("0.00")) != 0){
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("专辑限时优惠：" + derateAmount +"￥");
                orderDerateVoList.add(orderDerateVo);
            }

        }else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())){
            // 4. 处理声音（不允许重复
            // 4.1 调用远程专辑服务，得到待购买的声音列表
            List<TrackInfo> trackInfoList = albumFeignClient.getPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount()).getData();
            if (CollectionUtil.isEmpty(trackInfoList)){
                throw new GuiguException(400,"没有符合计算要求的声音");
            }

            // 4.2 根据声音id查询所在专辑列表得到声音单价
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId()).getData();
            BigDecimal price = albumInfo.getPrice();

            // 4.3 计算待购买的声音套餐价格
            originalAmount = price.multiply(new BigDecimal(trackInfoList.size()));
            orderAmount = originalAmount;

            // 4.4 封装本次订单中商品的清单列表
            orderDetailVoList = trackInfoList.stream()
                    .map(trackInfo -> {
                        OrderDetailVo orderDetailVo = new OrderDetailVo();
                        orderDetailVo.setItemId(trackInfo.getId());
                        orderDetailVo.setItemName(trackInfo.getTrackTitle());
                        orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                        orderDetailVo.setItemPrice(price);
                        return orderDetailVo;
                    }).collect(Collectors.toList());


        }


        // 5. 三种商品的订单信息数据
        // 5.1 封装购商品类型
        orderInfoVo.setItemType(tradeVo.getItemType());

        // 5.2 封装商品信息的相关价格
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);

        // 5.3 生成订单流水号
        // 5.3.1 构建当前用户本次订单流水号Key user:trade:16
        String tradeKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId;
        // 5.3.2 采取全局唯一字符串作为流水号value
        String tradeNo = IdUtil.randomUUID();
        // 5.3.3 将流水号存入Redis
        redisTemplate.opsForValue().setIfAbsent(tradeKey,tradeNo,5, TimeUnit.MINUTES);
        // 5.3.4 封装流水号
        orderInfoVo.setTradeNo(tradeNo);

        // 5.4 生成时间戳
        orderInfoVo.setTimestamp(DateUtil.current());

        // 5.5 生成订单签名
        // 5.5.1 将订单VO转为Map TODO:无法确认支付方式 将PayWay空属性排除
        Map<String, Object> map = BeanUtil.beanToMap(orderInfoVo, false, true);
        // 5.5.2 生成签名
        String sign = SignHelper.getSign(map);
        orderInfoVo.setSign(sign);

        // 6. 返回订单VO对象
        return orderInfoVo;
    }
}
